package com.lcredu.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * @author 黎长容
 * @date 2025-08-10 14:46
 */
@SpringBootApplication
public class MainApp {
    //为什么执行到run方法时,怎么启动了tomcat

    /**
     * 1.SpringApplication.java
     * 
     *     public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
     *         return run(new Class[]{primarySource}, args);
     *     }
     * 
     * 2.SpringApplication.java
     * 
     *     public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
     *         return (new SpringApplication(primarySources)).run(args);
     *     }
     *     
     * 3.SpringApplication.java   初始化阶段: 上下文创建 刷新上下文
     * 
     * public ConfigurableApplicationContext run(String... args) {
     *         StopWatch stopWatch = new StopWatch();
     *         stopWatch.start();
     *         DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
     *         ConfigurableApplicationContext context = null;
     *         this.configureHeadlessProperty();
     *         SpringApplicationRunListeners listeners = this.getRunListeners(args);
     *         listeners.starting(bootstrapContext, this.mainApplicationClass);
     *
     *         Throwable ex;
     *         try {
     *             ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
     *             ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
     *             this.configureIgnoreBeanInfo(environment);
     *             Banner printedBanner = this.printBanner(environment);
     *             //严重分析这个方法 createApplicationContext(), 会创建容器
     *             context = this.createApplicationContext();
     *             context.setApplicationStartup(this.applicationStartup);
     *             this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
     *             //严重分析这个方法 refreshContext(), 完成
     *             this.refreshContext(context);
     *             this.afterRefresh(context, applicationArguments);
     *             stopWatch.stop();
     *             if (this.logStartupInfo) {
     *                 (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
     *             }
     *
     *             listeners.started(context);
     *             this.callRunners(context, applicationArguments);
     *         } catch (Throwable var10) {
     *             ex = var10;
     *             this.handleRunFailure(context, ex, listeners);
     *             throw new IllegalStateException(ex);
     *         }
     *
     *         try {
     *             listeners.running(context);
     *             return context;
     *         } catch (Throwable var9) {
     *             ex = var9;
     *             this.handleRunFailure(context, ex, (SpringApplicationRunListeners)null);
     *             throw new IllegalStateException(ex);
     *         }
     *     }
     *     
     * 5.SpringApplication.java  传入webApplicationType参数指定Web应用类型 这里是SERVLET
     * 
     *     protected ConfigurableApplicationContext createApplicationContext() {
     *         return this.applicationContextFactory.create(this.webApplicationType);
     *     }
     *     
     *6.ApplicationContextFactory.java 创建容器 这里创建的是AnnotationConfigServletWebServerApplicationContext
     * 
     *     ApplicationContextFactory DEFAULT = (webApplicationType) -> {
     *         try {
     *             switch (webApplicationType) {
     *                 case SERVLET:
     *                     return new AnnotationConfigServletWebServerApplicationContext();
     *                 case REACTIVE:
     *                     return new AnnotationConfigReactiveWebServerApplicationContext();
     *                 default:
     *                     return new AnnotationConfigApplicationContext();
     *             }
     *         } catch (Exception var2) {
     *             Exception ex = var2;
     *             throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", ex);
     *         }
     *     };
     *     
     *
     * 6.SpringApplication 调用refresh方法刷新应用上下文
     * 
     *     private void refreshContext(ConfigurableApplicationContext context) {
     *         if (this.registerShutdownHook) {
     *             shutdownHook.registerApplicationContext(context);
     *         }
     *
     *         this.refresh(context);
     *     }
     *     
     *     
     *7.SpringApplication.java 刷新Spring应用程序上下文
     *     protected void refresh(ConfigurableApplicationContext applicationContext) {
     *         applicationContext.refresh();
     *     }
     *     
     *8.
     * 	    @Override
     *    public final void refresh() throws BeansException, IllegalStateException {
     * 		try {
     * 			super.refresh();
     *        }
     * 		catch (RuntimeException ex) {
     * 			WebServer webServer = this.webServer;
     * 			if (webServer != null) {
     * 				webServer.stop();
     *            }
     * 			throw ex;
     *        }
     *    }
     *    
     *    
     *9.ServletWebServerApplicationContext.java  调用父类的refresh()方法来刷新应用上下文
     * @Override
     * 	    public final void refresh() throws BeansException, IllegalStateException {
     * 		try {
     * 			super.refresh();
     *        }
     * 		catch (RuntimeException ex) {
     * 			WebServer webServer = this.webServer;
     * 			if (webServer != null) {
     * 				webServer.stop();
     *            }
     * 			throw ex;
     *        }
     *    }
     *    
     *    
     * 10.AbstractApplicationContext.java
     *      准备刷新：设置启动时间、激活状态等。
     *      获取新的BeanFactory：由子类实现具体创建或加载Bean定义。
     *      预处理BeanFactory：配置类加载器、表达式解析器、注册Aware接口回调等。
     *      调用BeanFactory后置处理器：执行自定义的BeanFactory修改逻辑。
     *      注册Bean后置处理器：用于拦截bean创建过程。
     *      初始化消息源、事件广播器等特殊bean。
     *      实例化非懒加载单例bean。
     *      完成刷新：发布上下文刷新完成事件。
     *      异常处理：出错时销毁已创建的bean并重置状态。
     *      清理缓存：释放反射元数据缓存。
     * 	    @Override
     *    public void refresh() throws BeansException, IllegalStateException {
     * 		synchronized (this.startupShutdownMonitor) {
     * 			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
     *
     * 			// Prepare this context for refreshing.
     * 			prepareRefresh();
     *
     * 			// Tell the subclass to refresh the internal bean factory.
     * 			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
     *
     * 			// Prepare the bean factory for use in this context.
     * 			prepareBeanFactory(beanFactory);
     *
     * 			try {
     * 				// Allows post-processing of the bean factory in context subclasses.
     * 				postProcessBeanFactory(beanFactory);
     *
     * 				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
     * 				// Invoke factory processors registered as beans in the context.
     * 				invokeBeanFactoryPostProcessors(beanFactory);
     *
     * 				// Register bean processors that intercept bean creation.
     * 				registerBeanPostProcessors(beanFactory);
     * 				beanPostProcess.end();
     *
     * 				// Initialize message source for this context.
     * 				initMessageSource();
     *
     * 				// Initialize event multicaster for this context.
     * 				initApplicationEventMulticaster();
     *
     * 				// Initialize other special beans in specific context subclasses.
     * 			//注意这个方法,完成刷新工作	
     * 				onRefresh();
     *
     * 				// Check for listener beans and register them.
     * 				registerListeners();
     *
     * 				// Instantiate all remaining (non-lazy-init) singletons.
     * 				finishBeanFactoryInitialization(beanFactory);
     *
     * 				// Last step: publish corresponding event.
     * 				finishRefresh();
     *            }
     *
     * 			catch (BeansException ex) {
     * 				if (logger.isWarnEnabled()) {
     * 					logger.warn("Exception encountered during context initialization - " +
     * 							"cancelling refresh attempt: " + ex);
     *                }
     *
     * 				// Destroy already created singletons to avoid dangling resources.
     * 				destroyBeans();
     *
     * 				// Reset 'active' flag.
     * 				cancelRefresh(ex);
     *
     * 				// Propagate exception to caller.
     * 				throw ex;
     *            }
     *
     * 			finally {
     * 				// Reset common introspection caches in Spring's core, since we
     * 				// might not ever need metadata for singleton beans anymore...
     * 				resetCommonCaches();
     * 				contextRefresh.end();
     *            }
     *        }
     *    }
     *    
     *11.ServletWebServerApplicationContext.java 
     *      该方法在Spring应用上下文刷新时调用，首先调用父类的onRefresh()方法，然后尝试创建Web服务器。
     *      如果创建过程中发生异常，则抛出ApplicationContextException并附带原始异常信息。
     *	    @Override
     *    protected void onRefresh() {
     * 		super.onRefresh();
     * 		try {
     * 			createWebServer();
     *        }
     * 		catch (Throwable ex) {
     * 			throw new ApplicationContextException("Unable to start web server", ex);
     *        }
     *    }
     *    
     *12.ServletWebServerApplicationContext.java        该方法用于创建Web服务器。
     * private void createWebServer() {
     * 		WebServer webServer = this.webServer;
     * 		ServletContext servletContext = getServletContext();
     * 		if (webServer == null && servletContext == null) {
     * 			StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
     * 		//获取ServletWebServerFactory 对象	
     * 			ServletWebServerFactory factory = getWebServerFactory();
     * 			createWebServer.tag("factory", factory.getClass().toString());
     * 			this.webServer = factory.getWebServer(getSelfInitializer());
     * 			createWebServer.end();
     * 			getBeanFactory().registerSingleton("webServerGracefulShutdown",
     * 					new WebServerGracefulShutdownLifecycle(this.webServer));
     * 			getBeanFactory().registerSingleton("webServerStartStop",
     * 					new WebServerStartStopLifecycle(this, this.webServer));
     * 		        }
     * 		else if (servletContext != null) {
     * 			try {
     * 				getSelfInitializer().onStartup(servletContext);
     *            }
     * 			catch (ServletException ex) {
     * 				throw new ApplicationContextException("Cannot initialize servlet context", ex);
     *            }
     *        }
     * 		initPropertySources();    * 	}
     * 	
     *13.TomcatServletWebServerFactory.java     该方法用于创建并配置一个嵌入式的Tomcat Web服务器实例。
     * 	    @Override
     *    public WebServer getWebServer(ServletContextInitializer... initializers) {
     * 		if (this.disableMBeanRegistry) {
     * 			Registry.disableRegistry();
     *        }
     * 		Tomcat tomcat = new Tomcat();
     * 		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
     * 		tomcat.setBaseDir(baseDir.getAbsolutePath());
     * 		Connector connector = new Connector(this.protocol);
     * 		connector.setThrowOnFailure(true);
     * 		tomcat.getService().addConnector(connector);
     * 		customizeConnector(connector);
     * 		tomcat.setConnector(connector);
     * 		tomcat.getHost().setAutoDeploy(false);
     * 		configureEngine(tomcat.getEngine());
     * 		for (Connector additionalConnector : this.additionalTomcatConnectors) {
     * 			tomcat.getService().addConnector(additionalConnector);
     *        }
     * 		prepareContext(tomcat.getHost(), initializers);
     * 		return getTomcatWebServer(tomcat);
     *    }
     *    
     *14.TomcatServletWebServerFactory.java  判断是否需要创建
     * 
     * 	protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
     * 		return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
     * 	    }
     *
     *15.TomcatWebServer.java 启动了tomcat
     * public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
     * 		Assert.notNull(tomcat, "Tomcat Server must not be null");
     * 		this.tomcat = tomcat;
     * 		this.autoStart = autoStart;
     * 		this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
     * 		initialize();
     * 	    }
     *
     * 	private void initialize() throws WebServerException {
     * 		logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
     * 		synchronized (this.monitor) {
     * 			try {
     * 				addInstanceIdToEngineName();
     *
     * 				Context context = findContext();
     * 				context.addLifecycleListener((event) -> {
     * 					if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
     * 						// Remove service connectors so that protocol binding doesn't
     * 						// happen when the service is started.
     * 						removeServiceConnectors();
     *                    }
     *                });
     *
     * 				// Start the server to trigger initialization listeners
     * 			//启动咯	
     * 				this.tomcat.start();
     *
     * 				// We can re-throw failure exception directly in the main thread
     * 				rethrowDeferredStartupExceptions();
     *
     * 				try {
     * 					ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
     *                }
     * 				catch (NamingException ex) {
     * 					// Naming is not enabled. Continue
     *                }
     *
     * 				// Unlike Jetty, all Tomcat threads are daemon threads. We create a
     * 				// blocking non-daemon to stop immediate shutdown
     * 				startDaemonAwaitThread();
     *            }
     * 			catch (Exception ex) {
     * 				stopSilently();
     * 				destroySilently();
     * 				throw new WebServerException("Unable to start embedded Tomcat", ex);
     *            }
     *        }
     */
    public static void main(String[] args) {
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
        if (ioc.containsBean("dog") && ioc.containsBean("config")) {
            System.out.println("hello,dog");
        }
    }
}
